﻿/***************************************************************
*       
* add by OceanHo 2015/8/22 16:08:24
*
****************************************************************/

using oceanho.webapi.factory.httpAttr;
using oceanho.webapi.factory.httpCore;
using oceanho.webapi.factory.httpCore.Binder;
using oceanho.webapi.factory.httpEntity;
using oceanho.webapi.factory.httpUtility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;

namespace oceanho.webapi.factory.httpHandler
{
    /// <summary>
    /// 定义：通过实现 IHttpHandler接口，完成对请求拦截处理的入口类。
    /// 除了实现 IHttpHandler接口，此类本身还添加了一些常用方法，用于处理一般性HTTP,GET/POST请求，轻量级实现，可以满足您一般API接口应用程序需要以及自定义扩展
    /// </summary>
    public class http_service_handler : IHttpHandler
    {
        #region IHttpHandler

        public bool IsReusable
        {
            get { return false; }
        }

        [UnAllowCallMethod]
        public void ProcessRequest(HttpContext context)
        {
            Context = context;

            // 只支持 http GET/POST 
            if (Request.HttpMethod != "GET" && Request.HttpMethod != "POST")
            {
                Send403("Unsuport method：{0}", Request.HttpMethod);
                FlushAndEnd();
                return;
            }

            // 定义与初始化调用函数系统内置参数（如OnServer404函数等等）
            RunHandlerEvent arg = RunEventUtility.CreateHandlerEvent();

            // 解析当前请求执行的调用方法（如果解析失败，将返回null，如果解析成功，返回对应的调用方法）
            System.Reflection.MethodInfo method = ReqResolverUtility.ResolveReq(GetType(), Request);
            if (method == null)
            {
                arg.Handled = false;
                OnServer404(arg);
                FlushAndEnd();
                return;
            }

            //-- 找到了需要执行的义务方法,接下来就是创建对于执行参数,调用该方法了 --//
            arg.Handled = false;
            arg.ActionName = method.Name;
            arg.ActionParameters = method.GetParameters();
            arg.CustomAttributes = method.GetCustomAttributes(true);

            try
            {
                // set1
                // 执行义务方法前执行OnExcuting
                OnExcuting(arg);
                if (arg.Handled) { return; }


                // set2 , 执行OnBinder()方法,详见 CallMethod()中
                // --------------------------------------------//
                // set3
                // 调用请求处理函数（该方法里面会调用 set2 的OnBinder函数）
                ResolveParameterAndCallMethod(method);

                // set4 (callmethod没有引发异常)
                // 调用（执行某个Action方法后的需要执行的OnExcuted）
                OnExcuted(context);
            }
            catch (Exception ex)
            {
                // 重置回调参数的Handled
                arg.Handled = false;

                // set 4 (callmethod引发了异常的情况下)
                OnServer500(arg);
                if (!arg.Handled)
                {
                    throw ex.InnerException == null ? ex : ex.InnerException;
                }
            }
            finally
            {
                FlushAndEnd();
            }
        }
        #endregion

        #region -- 自定义属性 --

        protected HttpContext Context
        {
            get;
            private set;
        }
        protected HttpRequest Request
        {
            get
            {
                return Context.Request;
            }
        }

        protected HttpResponse Response
        {
            get
            {
                return Context.Response;
            }
        }

        protected HttpServerUtility Server
        {
            get
            {
                return Context.Server;
            }
        }

        #endregion

        #region -- 自定义方法 Upload/Download --

        /// <summary>
        /// 定义一个上传文件的方法
        /// </summary>
        /// <param name="arg">上传参数</param>        
        protected virtual void Upload(UploadParameter arg)
        {
            Hashtable _fileHash = new Hashtable();
            try
            {
                // 验证上传文件的合法性,如果成功,上传文件。
                if (FileUploadUtility.IsValid(arg))
                    FileUploadUtility.SaveToDisk(arg, _fileHash);
                // throw new InvalidDataException("上传参数验证失败,请确认重试");
            }
            catch (Exception ex)
            {
                FileUploadUtility.DoTranstion(arg, _fileHash);
                throw ex;
            }
            finally
            {
                _fileHash.Clear();
            }
        }

        /// <summary>
        /// 定义一个下载文件的方法
        /// </summary>
        /// <param name="arg">下载参数</param>        
        protected virtual void Download(DownloadParameter arg)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region -- 内部实现方法 Content/Html/Json/Jsonp --

        /// <summary>
        /// 输出文本
        /// </summary>
        /// <param name="content">文本内容</param>
        /// <param name="formaters">针对文本内容的formater参数</param>        
        protected void Content(string content, params object[] formaters)
        {
            SendContent(content, MimeTypes.Html, null, formaters);
        }

        /// <summary>
        /// 输出Content-Type为text/html字符
        /// </summary>
        /// <param name="content">文本内容</param>
        /// <param name="formaters">针对文本内容的formater参数</param>        
        protected void Html(string content, params object[] formaters)
        {
            SendContent(content, MimeTypes.Html, null, formaters);
        }

        /// <summary>
        /// 输出Content-Type为application/json字符
        /// </summary>
        /// <param name="result">json格式的字符串或者需要转换为json字符串包含数据的对象</param>        
        protected void Json(object result)
        {
            Json(result, JsonAllowOption.Default);
        }

        /// <summary>
        /// 输出Content-Type为application/json字符
        /// </summary>
        /// <param name="result">json格式的字符串或者需要转换为json字符串包含数据的对象</param>
        /// <param name="allowOption">对于json获取的Method允许枚举</param>        
        protected void Json(object result, JsonAllowOption allowOption)
        {
            if (result != null &&
                CommonUtility.TypeIsValueTypeOrString(result.GetType()))
            {
                result = Newtonsoft.Json.JsonConvert.SerializeObject(result);
            }

            if (allowOption != JsonAllowOption.AllowGet && Request.HttpMethod == "GET")
            {
                Send403(" not allow GET method do ");
                return;
            }

            SendContent(result.ToString(), MimeTypes.Json, Request.ContentEncoding);
        }

        /// <summary>
        /// 输出Content-Type为application/javascript字符，输出内容为[ 参数call+scriptOrScriptData]
        /// </summary>
        /// <param name="call">客户端回调js函数名称</param>
        /// <param name="result">客户端回调js函数所需的参数字符串或者所需json格式包含数据的对象</param>        
        protected void Jsonp(string call, object result)
        {
            if (result != null &&
                CommonUtility.TypeIsValueTypeOrString(result.GetType()))
            {
                result = Newtonsoft.Json.JsonConvert.SerializeObject(result);
            }
            result = call + "(" + result + ");";
            SendContent(result.ToString(), MimeTypes.Script);
        }
        #endregion

        #region -- 辅助类方法 -> ResolveParameterAndCallMethod
        private object ResolveParameterAndCallMethod(System.Reflection.MethodInfo method)
        {
            object[] objParams = null;
            System.Reflection.ParameterInfo[] parameters = method.GetParameters();
            if (parameters != null && parameters.Length > 0)
            {
                objParams = new object[parameters.Length];
                for (int i = 0; i < parameters.Length; i++)
                {
                    objParams[i] = OnBinder(parameters[i]);
                }
            }
            return method.Invoke(this, objParams);
        }
        #endregion

        #region -- 自定义方法 OnBinder/OnExcuting/OnExcuted --

        /// <summary>
        /// 根据HttpRequest提供的参数与当前请求的义务方法参数，创建义务参数所需的参数对象
        /// </summary>
        /// <param name="parameterInfo">参数元数据对象</param>
        /// <returns></returns>        
        protected virtual object OnBinder(System.Reflection.ParameterInfo parameterInfo)
        {

            object[] objAttries = parameterInfo.GetCustomAttributes(typeof(ParamBinderAttribute), true);
            if (objAttries != null && objAttries.Length > 0)
            {
                return ((ParamBinderAttribute)objAttries[0]).Binder.GetModel(parameterInfo, Context);
            }
            return new DefaultBinder().GetModel(parameterInfo, Context);
        }

        /// <summary>
        /// 定义一个执行请求的方法前的回调执行函数
        /// </summary>        
        protected virtual void OnExcuting(RunHandlerEvent argument)
        {

        }

        /// <summary>
        /// 定义一个执行请求的方法后（输出内容前,在调用Flush前）的回调执行函数（比如设置自定义http头,cookie类的操作）
        /// </summary>        
        protected virtual void OnExcuted(HttpContext context)
        {
            // context.Response.ClearContent();
            // context.Response.Cookies.Add(new HttpCookie("app_id", "123456"));
        }

        #endregion

        #region -- 内部实现方法 OnServer500/OnServer404/OnServer403 --

        protected void OnServer500(RunHandlerEvent handler)
        {
            // 服务器 500 错误,默认不处理。直接把异常信息抛出来
            //handler.Handled = false;
            //Content("server {0} error ", 500);
            //Send500();
        }

        protected void OnServer404(RunHandlerEvent handler)
        {
            handler.Handled = true;
            Content("resources not found , {0} ", 404);
            Send404();
        }

        protected void OnServer403(RunHandlerEvent handler)
        {
            handler.Handled = true;
            Content("no access , {0} ", 403);
            Send403();
        }
        #endregion

        #region -- 内部实现方法 -> Send403/Send404/Send500/SendCode/SendContent/FlushAndEnd --

        protected void Send403(string desc = null, params object[] formaters)
        {
            SendCode(403, desc, formaters);
        }

        protected void Send404(string desc = null, params object[] formaters)
        {
            SendCode(404, desc, formaters);
        }

        protected void Send500(string desc = null, params object[] formaters)
        {
            SendCode(500, desc);
        }

        protected void SendCode(int code, string desc, params object[] formaters)
        {
            Response.StatusCode = code;
            if (!string.IsNullOrEmpty(desc))
            {
                desc = string.Format(desc, formaters);
            }
            Response.StatusDescription = desc;
        }

        protected void SendContent(string content, string contentType, Encoding encoding = null, params object[] formaters)
        {
            if (encoding != null)
                Response.ContentEncoding = encoding;
            if (formaters.Length > 0)
                content = string.Format(content, formaters);

            Response.ContentType = contentType;
            Response.Write(content);
            // Response.Flush(); 会发送http头给服务端，调用此方法后不可以再设置任何http头信息
        }

        /// <summary>
        /// 调用 Response.Flush(),Context.ApplicationInstance.CompleteRequest()结束本次请求处理
        /// </summary>
        private void FlushAndEnd()
        {
            try
            {
                Response.Flush();
                Context.ApplicationInstance.CompleteRequest();
            }
            catch { }
            // Response.End();
        }
        #endregion
    }
}
